package hydrap2p.helper;

import hydrap2p.ServiceLocation;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;

public class PooledProtocolManager {

	private static Map<ServiceLocation, List<TTransport>> idleTransports = new HashMap<ServiceLocation, List<TTransport>>();
	private static Map<ServiceLocation, List<TTransport>> busyTransports = new HashMap<ServiceLocation, List<TTransport>>();
	
	public static TTransport checkout(ServiceLocation location) throws TTransportException
	{
		List<TTransport> idles;
		List<TTransport> busys;
		TTransport connection=null;
		
		// create the pools for the given location
		synchronized(idleTransports)
		{
			if (!idleTransports.containsKey(location)) {
				idles=new LinkedList<TTransport>();
				idleTransports.put(location, idles);
			}
			else
				idles=idleTransports.get(location);
		}
		synchronized(busyTransports)
		{
			if (!busyTransports.containsKey(location)) {
				busys=new LinkedList<TTransport>();
				busyTransports.put(location, busys);
			}
			else
				busys=busyTransports.get(location);
		}
		
		// Create a new connection, or pull one from the idle pool
		synchronized(idles)
		{
			// If there are no idle ones, make a new connection
			if (idles.size()==0)
			{
				connection = new TSocket(location.address,location.port);
				connection.open();
			}
			else
			{
				connection=idles.remove(0);
			}
		}
		
		// Add it to the busy list
		synchronized(busys)
		{
			busys.add(connection);
		}
		return connection;
	}

	public static void checkin(ServiceLocation location, TTransport connection)
	{
		List<TTransport> idles;
		List<TTransport> busys;
		
		// Get the list of idle transports for this service location
		synchronized(idleTransports)
		{
			idles=idleTransports.get(location);
		}
		
		// Get the list of busy transports for this service location
		synchronized(busyTransports)
		{
			busys=busyTransports.get(location);
		}
		
		// Remove this transport from the busy list
		int index=-1;
		synchronized(busys)
		{
			index=busys.indexOf(connection);
			if (index>-1)
			{
				busys.remove(index);
			}
		}
		// Add it to the idle list
		synchronized(idles)
		{
			if (index>-1)
				idles.add(connection);
		}
	}

	public static void close(ServiceLocation location, TTransport connection)
	{
		List<TTransport> busys;
		
		// Get the list of busy transports for this service location
		synchronized(busyTransports)
		{
			busys=busyTransports.get(location);
		}
		
		// Remove this transport from the busy list
		synchronized(busys)
		{
			int index=busys.indexOf(connection);
			if (index>-1)
			{
				busys.remove(index);
			}
			
			try {
				connection.close();
			}
			catch (Exception e)
			{}
		}
	}
}
